package com.zmn.oms.dubbo.impl.zmn.normal.erp;

import com.google.common.collect.Lists;
import com.zmn.base.channel.common.dro.ChannelDRO;
import com.zmn.base.channel.dubbo.interfaces.channel.ChannelListRemoteService;
import com.zmn.base.common.data.common.dro.area.AreaDRO;
import com.zmn.base.common.data.dubbo.interfaces.area.AreaListRemoteService;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.map.Point;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.oms.business.interfaces.baidumap.BaiduMapBService;
import com.zmn.oms.business.interfaces.work.tag.OrderTagBService;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.OrderPartConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.common.constant.OrderTagConsts;
import com.zmn.oms.common.utils.FilterUtil;
import com.zmn.oms.common.utils.MathUtil;
import com.zmn.oms.dubbo.dto.zmn.erp.*;
import com.zmn.oms.dubbo.interfaces.zmn.normal.erp.ZsErpAccountListRemoteService;
import com.zmn.oms.dubbo.utils.DubboConsts;
import com.zmn.oms.model.entity.detail.OrderDetail;
import com.zmn.oms.model.entity.discount.OrderDiscount;
import com.zmn.oms.model.entity.factory.OrderFactory;
import com.zmn.oms.model.entity.master.OrderMaster;
import com.zmn.oms.model.entity.order.OrderExtend;
import com.zmn.oms.model.entity.part.OrderPart;
import com.zmn.oms.model.entity.pay.OrderPay;
import com.zmn.oms.model.entity.serviceitem.OrderServiceItem;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.discount.OrderDiscountService;
import com.zmn.oms.services.interfaces.factory.OrderFactoryService;
import com.zmn.oms.services.interfaces.master.OrderMasterService;
import com.zmn.oms.services.interfaces.order.OrderExtendService;
import com.zmn.oms.services.interfaces.part.OrderPartService;
import com.zmn.oms.services.interfaces.pay.OrderPayService;
import com.zmn.oms.services.interfaces.serviceitem.OrderServiceItemService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.pay.common.constant.PayConsts;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author sunlife
 * @date:2020/9/15 11:16 上午
 * description:
 */
@Slf4j
@Service(loadbalance = "roundrobin", timeout = 5000, retries = 2, version = DubboConsts.INTERFACE_VERSION, validation = "false")
public class ZsErpAccountListRemoteServiceImpl implements ZsErpAccountListRemoteService {

    @Autowired
    private OrderWorkService orderWorkService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderExtendService orderExtendService;
    @Autowired
    private OrderFactoryService orderFactoryService;
    @Autowired
    private OrderDiscountService orderDiscountService;
    @Autowired
    private BaiduMapBService baiduMapBService;
    @Autowired
    private OrderServiceItemService orderServiceItemService;
    @Autowired
    private OrderMasterService orderMasterService;
    @Autowired
    private OrderPartService orderPartService;
	@Autowired
	private OrderPayService orderPayService;
    @Autowired
    private OrderTagBService orderTagBService;

    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    private ChannelListRemoteService channelListRemoteService;
    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    private AreaListRemoteService areaListRemoteService;

    @Override
    public ResponseDTO<OmsErpNewOrderAccountDRO> getNewOrderAccountInfoByOrderIdAndWorkId(@Valid @NotNull(message = "orderId不能为空") Long orderId, @Valid @NotNull(message = "workId不能为空") Long workId) {
        if (Objects.isNull(orderId) || Objects.isNull(workId)) {
            return ResponseDTO.fail("ID不能为空");
        }
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        if (Objects.isNull(orderWork)) {
            return ResponseDTO.fail("工单不存在");
        }
        if (!Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_NEW)) {
            return ResponseDTO.fail("工单非新单，请调用其他服务接口");
        }

        OrderDetail orderDetail = orderDetailService.findOrderDetailByKeySrcMaster(workId);


        // 工单信息设置
        OmsErpNewOrderAccountDRO newOrderAccountDRO = BeanMapper.map(orderWork, OmsErpNewOrderAccountDRO.class);

        newOrderAccountDRO.setOrderType(orderWork.getType());
        newOrderAccountDRO.setOrderCityId(orderWork.getCityId());
        newOrderAccountDRO.setOrderCityName(orderDetail.getCityName());
        newOrderAccountDRO.setPlatSource(orderWork.getPlat());
        newOrderAccountDRO.setPlat(orderWork.getPlatWork());
        newOrderAccountDRO.setSubCompanyId(orderWork.getCompanyId());
        newOrderAccountDRO.setSubCompanyName(orderWork.getCompanyName());
        newOrderAccountDRO.setSpCompanyId(orderWork.getManageCompanyId());
        newOrderAccountDRO.setSpCompanyName(orderWork.getManageCompanyName());
        newOrderAccountDRO.setProductGroupId(orderWork.getServProductGroupId());
        newOrderAccountDRO.setProductGroupName(orderWork.getServProductGroupName());
        newOrderAccountDRO.setOrderSourceType(orderWork.getSourceType());
        newOrderAccountDRO.setServCategName(orderWork.getShowServCategName());

        newOrderAccountDRO.setUserName(orderDetail.getUserName());
        newOrderAccountDRO.setEngSupervisorId(orderWork.getMasterSupervisorId());
        newOrderAccountDRO.setEngSupervisorName(orderWork.getMasterSupervisorName());
        newOrderAccountDRO.setOrderSuccessful(Objects.equals(orderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_SUCCESS));

        // 配件金额
        List<OrderPart> orderParts = orderPartService.listByOrderId(orderId);

        // 将报销失败的【外报或运杂】配件移除
        orderParts.removeIf(orderPart -> Objects.equals(orderPart.getReimburseStatus(), OrderConsts.PART_REIMBURSE_STATUS_FAIL)
                && (Objects.equals(orderPart.getPartType(), OrderConsts.PART_TYPE_SOURCING_OUT) ||
                Objects.equals(orderPart.getPartType(), OrderConsts.PART_TYPE_DELIVER)));

        Integer partAmount = orderParts.stream().mapToInt(part -> {
            return MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber());
        }).sum();
        newOrderAccountDRO.setPartAmount(partAmount);

        // 使用来源渠道sourceChannelId（专门用来做结算使用） 进行erp算账
        // 默认情况下 sourceChannelId 和 channelId 是相同的 只有营销推广业务这种sourceChannelId 和 channelId不同
        // 不同 eg. 通过啄金客账户推广 用户扫推广码码到我们微信公众号下的定单 sourceChannelId 是啄金客二级渠道 channelId 就是微信公众号二级渠道
        Integer channel = NumberUtil.isNullOrZero(orderWork.getSourceChannelId()) ?
                orderWork.getChannelId() :
                orderWork.getSourceChannelId();
        newOrderAccountDRO.setChannelId(channel);
        ResponseDTO<ChannelDRO>  channelDROResponseDTO = channelListRemoteService.getByChannelId(channel);
        if (channelDROResponseDTO.isSuccess()) {
            newOrderAccountDRO.setChannelName(channelDROResponseDTO.getData().getName());
        }


        // 厂商id
        if (Objects.equals(orderWork.getSourceType(), OrderConsts.ORDER_SOURCE_TYPE_FACTORY)) {
            OrderFactory orderFactory = orderFactoryService.findOrderFactoryByKey(orderWork.getOrderId());
            if (orderFactory != null) {
                newOrderAccountDRO.setFactoryId(orderFactory.getFactoryId());
            }
        }

        // 行车距离
        // 获取区县经纬度
        ResponseDTO<AreaDRO> areaDROResponseDTO = areaListRemoteService.getById(orderDetail.getCountyId());
        if (areaDROResponseDTO.isSuccess()) {
            Point point1 = new Point(areaDROResponseDTO.getData().getLongitude(), areaDROResponseDTO.getData().getLatitude());
            Point point2 = new Point(orderDetail.getLongitude(), orderDetail.getLatitude());
            newOrderAccountDRO.setDistanceValue(baiduMapBService.getNavigationDistance(point1, point2));
        }

        // 处理工程师信息
        // 当前工单多工程师处理
        // 查询工程师列表
        List<OrderMaster> orderMasterList = orderMasterService.listMasterByWorkId(orderWork.getOrderId(), orderWork.getWorkId());
        Map<Integer,  List<OrderPart>> partMap = orderParts.stream()
                .collect(Collectors.groupingBy(OrderPart::getMasterId));

        List<OmsErpOrderAccountEngineerDRO> multiMasters = new ArrayList<>(orderMasterList.size());
        orderMasterList.forEach(orderMaster -> {
            OmsErpOrderAccountEngineerDRO engineerDRO = new OmsErpOrderAccountEngineerDRO();
            engineerDRO.setEngineerId(orderMaster.getMasterId());
            engineerDRO.setEngineerName(orderMaster.getMasterName());
            engineerDRO.setMajorEngineer(Objects.equals(orderMaster.getType(), OrderConsts.ORDER_MASTER_TYPE_MAIN));

            List<OrderPart> orderMasterParts = partMap.get(orderMaster.getMasterId());
            if (CollectionUtil.isNotNullOrEmpty(orderMasterParts)) {
                // 内采&非质保金购买
                Integer noDepositpartAmount = orderMasterParts.stream().filter(part -> Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_IN) && !Objects.equals(part.getPayType(), OrderPartConsts.DEPOSIT_PAY)).mapToInt(part -> {
                    return MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber());
                }).sum();
                // 内采&非质保金购买
                Integer masterSupPartAmount = orderMasterParts.stream().filter(part -> Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_IN) && Objects.equals(part.getPayType(), OrderPartConsts.DEPOSIT_PAY)).mapToInt(part -> {
                    return MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber());
                }).sum();
                // 非内采配件
                Integer otherPartAmount = orderMasterParts.stream().filter(part -> !Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_IN)).mapToInt(part -> {
                    return MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber());
                }).sum();

                engineerDRO.setPartAmount(noDepositpartAmount);
                engineerDRO.setPartAmountFromSup(masterSupPartAmount);
                engineerDRO.setOtherPartAmount(otherPartAmount);
            }
            multiMasters.add(engineerDRO);
        });
        newOrderAccountDRO.setEngineers(multiMasters);

        // 优惠券
        List<OrderDiscount> orderDiscounts = orderDiscountService.listByOrderId(orderWork.getOrderId()).stream().filter(discount -> NumberUtil.isNotNullOrZero(discount.getAmount())).collect(Collectors.toList());
        newOrderAccountDRO.setDiscountList(BeanMapper.mapList(orderDiscounts, OmsErpOrderDiscountDRO.class));
        newOrderAccountDRO.setVasPreSellAmount(orderWork.getDiscountPrepayAmount());

        // 支付凭证
		List<OrderPay> orderPays = orderPayService.listOrderPayByOrderIdAndWorkId(orderId, workId);
        if (!CollectionUtils.isEmpty(orderPays)) {
            List<OmsErpOrderPayDRO> erpOrderPayDROS = Lists.newArrayList();
			orderPays.forEach(e -> {
                if (Objects.equals(e.getDuplicate(), GlobalConsts.YES)) {
                    log.info("{}重复支付不算入erp算账", e.getOrderId());
                    return;
                }
                OmsErpOrderPayDRO erpOrderPayDRO = BeanMapper.map(e, OmsErpOrderPayDRO.class);
                //erpOrderPayDRO.setPayId(e.getPayId());
				erpOrderPayDRO.setPayChannelName(PayConsts.getPayChannelName(e.getPayChannelId()));
				erpOrderPayDRO.setUnionPay(Objects.equals(e.getPayChannelId(), PayConsts.PAY_CHANNEL_THIRD_CHINAUMS) ?
						GlobalConsts.YES : GlobalConsts.NO);
                erpOrderPayDRO.setPayTargetChannelId(e.getPayTargetChannelId());
                erpOrderPayDRO.setPayType(e.getPayType());
                erpOrderPayDROS.add(erpOrderPayDRO);
            });
            newOrderAccountDRO.setOrderPayList(erpOrderPayDROS);
        }

        // 服务项内外结算价
        List<OrderServiceItem> orderServiceItems = orderServiceItemService.listByOrderId(orderWork.getOrderId());
        Integer internalSettlementPrice = 0;
        Integer externalSettlementPrice = 0;
        if (CollectionUtil.isNotNullOrEmpty(orderServiceItems)) {
            internalSettlementPrice = orderServiceItems.stream()
                    .filter(e -> NumberUtil.isNotNullOrZero(e.getInternalTotalPrice()))
                    .mapToInt(OrderServiceItem::getInternalTotalPrice).sum();
            externalSettlementPrice = orderServiceItems.stream()
                    .filter(e -> NumberUtil.isNotNullOrZero(e.getExternalTotalPrice()))
                    .mapToInt(OrderServiceItem::getExternalTotalPrice).sum();
        }
        if (NumberUtil.isNullOrZero(internalSettlementPrice)) {
            internalSettlementPrice = orderWork.getOriginalAmount();
        }
        if (NumberUtil.isNullOrZero(internalSettlementPrice)) {
            externalSettlementPrice = orderWork.getOriginalAmount();
        }
        newOrderAccountDRO.setInternalStatementAmount(internalSettlementPrice);
        newOrderAccountDRO.setOutStatementAmount(externalSettlementPrice);

        // 过滤用户名称的特殊字符
        newOrderAccountDRO.setUserName(FilterUtil.replaceSpeChar(newOrderAccountDRO.getUserName()));

        // 是否包含工单绩效剔除标记
        Boolean existsTag = orderTagBService.existsCategoryTagByCategoryId(orderWork.getOrderId(), orderWork.getWorkId(),
                OrderTagConsts.TAG_CATEGORY_ID_EXCLUDE_PERFORMANCE);
        newOrderAccountDRO.setEliminateTag(existsTag);
        log.info("ERP请求参数[{}]", newOrderAccountDRO);
        return ResponseDTO.success(newOrderAccountDRO);
    }

    @Override
    public ResponseDTO<OmsErpReworkOrderAccountDRO> getReworkOrderAccountInfoByOrderIdAndWorkId(@Valid @NotNull(message = "orderId不能为空") Long orderId, @Valid @NotNull(message = "workId不能为空") Long workId) {
        if (Objects.isNull(orderId) || Objects.isNull(workId)) {
            return ResponseDTO.fail("ID不能为空");
        }
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        if (Objects.isNull(orderWork)) {
            return ResponseDTO.fail("工单不存在");
        }
        if (!Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_REWORK)) {
            return ResponseDTO.fail("工单非返修单，请调用其他服务接口");
        }
        OmsErpReworkOrderAccountDRO reworkOrderAccountDRO = new OmsErpReworkOrderAccountDRO();
        reworkOrderAccountDRO.setSourceOrderId(orderWork.getOriginalId());
        reworkOrderAccountDRO.setOrderId(orderId);
        reworkOrderAccountDRO.setPlatSource(orderWork.getPlat());
        reworkOrderAccountDRO.setPlat(orderWork.getPlatWork());
        reworkOrderAccountDRO.setSubCompanyId(orderWork.getCompanyId());
        reworkOrderAccountDRO.setSubCompanyName(orderWork.getCompanyName());
        reworkOrderAccountDRO.setSpCompanyId(orderWork.getManageCompanyId());
        reworkOrderAccountDRO.setSpCompanyName(orderWork.getManageCompanyName());
        reworkOrderAccountDRO.setReceiveTime(orderWork.getReceiveTime());
        reworkOrderAccountDRO.setCompleteTime(orderWork.getCompleteTime());
        // 处理工程师信息
        // 当前工单多工程师处理
        // 查询工程师列表
        // 配件信息
        List<OrderPart> orderParts = orderPartService.listByOrderId(orderId);

        // 将报销失败的【外报或运杂】配件移除
        orderParts.removeIf(orderPart -> Objects.equals(orderPart.getReimburseStatus(), OrderConsts.PART_REIMBURSE_STATUS_FAIL)
                && (Objects.equals(orderPart.getPartType(), OrderConsts.PART_TYPE_SOURCING_OUT) ||
                Objects.equals(orderPart.getPartType(), OrderConsts.PART_TYPE_DELIVER)));

        List<OrderMaster> orderMasterList = orderMasterService.listMasterByWorkId(orderWork.getOrderId(), orderWork.getWorkId());

        Map<Integer,  List<OrderPart>> partMap = orderParts.stream()
                .collect(Collectors.groupingBy(OrderPart::getMasterId));

        List<OmsErpOrderAccountEngineerDRO> multiMasters = new ArrayList<>(orderMasterList.size());
        orderMasterList.forEach(orderMaster -> {
            OmsErpOrderAccountEngineerDRO engineerDRO = new OmsErpOrderAccountEngineerDRO();
            engineerDRO.setEngineerId(orderMaster.getMasterId());
            engineerDRO.setEngineerName(orderMaster.getMasterName());
            engineerDRO.setMajorEngineer(Objects.equals(orderMaster.getType(), OrderConsts.ORDER_MASTER_TYPE_MAIN));

            List<OrderPart> orderMasterParts = partMap.get(orderMaster.getMasterId());
            if (CollectionUtil.isNotNullOrEmpty(orderMasterParts)) {
                // 内采&非质保金购买
                Integer noDepositpartAmount = orderMasterParts.stream().filter(part -> Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_IN) && !Objects.equals(part.getPayType(), OrderPartConsts.DEPOSIT_PAY)).mapToInt(part -> {
                    return MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber());
                }).sum();
                // 内采&非质保金购买
                Integer masterSupPartAmount = orderMasterParts.stream().filter(part -> Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_IN) && Objects.equals(part.getPayType(), OrderPartConsts.DEPOSIT_PAY)).mapToInt(part -> {
                    return MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber());
                }).sum();
                // 非内采配件
                Integer otherPartAmount = orderMasterParts.stream().filter(part -> !Objects.equals(part.getPartType(), OrderConsts.PART_TYPE_SOURCING_IN)).mapToInt(part -> {
                    return MathUtil.amountMultiplyNumber(part.getPrice(), part.getNumber());
                }).sum();

                engineerDRO.setPartAmount(noDepositpartAmount);
                engineerDRO.setPartAmountFromSup(masterSupPartAmount);
                engineerDRO.setOtherPartAmount(otherPartAmount);
            }
            multiMasters.add(engineerDRO);
        });
        reworkOrderAccountDRO.setEngineers(multiMasters);
        return ResponseDTO.success(reworkOrderAccountDRO);
    }

    @Override
    public ResponseDTO<OmsErpRefundOrderAccountDRO> getRefundOrderAccountInfoByOrderIdAndWorkId(@Valid @NotNull(message = "orderId不能为空") Long orderId, @Valid @NotNull(message = "workId不能为空") Long workId) {
        if (Objects.isNull(orderId) || Objects.isNull(workId)) {
            return ResponseDTO.fail("ID不能为空");
        }
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        if (Objects.isNull(orderWork)) {
            return ResponseDTO.fail("工单不存在");
        }
        if (!Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_REFUND)) {
            return ResponseDTO.fail("工单非退款单，请调用其他服务接口");
        }

        OrderDetail orderDetail = orderDetailService.findOrderDetailByKeySrcMaster(orderId);
        OrderExtend orderExtend = orderExtendService.findOrderExtendByOrderId(orderId);

        OmsErpRefundOrderAccountDRO accountDRO = new OmsErpRefundOrderAccountDRO();
        accountDRO.setSourceWorkId(orderWork.getOrderId());
        accountDRO.setOrderId(orderWork.getOrderId());
        accountDRO.setWorkId(orderWork.getWorkId());
        accountDRO.setPlat(orderWork.getPlatWork());
        accountDRO.setServCategId(orderWork.getServCategId());
        accountDRO.setServCategName(orderWork.getShowServCategName());
        accountDRO.setRefundAmount(orderWork.getRefundAmount());
        accountDRO.setRefundCustomerName(orderDetail.getUserName());
        accountDRO.setReceiveTime(orderWork.getReceiveTime());
        accountDRO.setManageCompanyId(orderWork.getManageCompanyId());
        if (Objects.nonNull(orderExtend)) {
            accountDRO.setAllowRefund(orderExtend.getAllowRefund());
        }

        return ResponseDTO.success(accountDRO);
    }
}
